#!/usr/bin/python2.6

# Copyright (c) 2009 Google Inc. All rights reserved.
# Copyright (C) 2012 Sony Computer Entertainment Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Make the format of a vcproj really pretty.

   It outputs the resulting xml to stdout.
"""

import os
import sys

from xml.dom.minidom import parse
from xml.dom.minidom import Node

class CmpTuple:
  """Compare function between 2 tuple."""
  def __call__(self, x, y):
    (key1, value1) = x
    (key2, value2) = y
    return cmp(key1, key2)

class CmpNode:
  """Compare function between 2 xml nodes."""

  def get_string(self, node):
    node_string = "node"
    node_string += node.nodeName
    if node.nodeValue:
      node_string += node.nodeValue

    if node.attributes:
      # We first sort by name, if present.
      node_string += node.getAttribute("Name")

      all_nodes = []
      for (name, value) in node.attributes.items():
        all_nodes.append((name, value))

      all_nodes.sort(CmpTuple())
      for (name, value) in all_nodes:
        node_string += name
        node_string += value

    return node_string

  def __call__(self, x, y):
    return cmp(self.get_string(x), self.get_string(y))


def _write_data(writer, data):
    "Writes datachars to writer."
    data = data.replace("&", "&amp;").replace("<", "&lt;")
    data = data.replace("\"", "&quot;").replace(">", "&gt;")
    writer.write(data)

def _has_only_text_node(node):
    def is_text_node(node):
        return node.nodeType == Node.TEXT_NODE
    return all(map(is_text_node, node.childNodes))

def writexml(node, writer, indent="", addindent="", newl=""):
    # indent = current indentation
    # addindent = indentation to add to higher levels
    # newl = newline string
    writer.write(indent+"<" + node.tagName)

    attrs = node._get_attributes()
    a_names = attrs.keys()
    for a_name in a_names:
        writer.write(" %s=\"" % a_name)
        _write_data(writer, attrs[a_name].value)
        writer.write("\"")
    writer.write(">")

    if _has_only_text_node(node):
        for c in node.childNodes:
          writer.write(c.data)
        writer.write("</%s>%s" % (node.tagName, newl))
    else:
        writer.write("\n")
        for c in node.childNodes:
            writexml(c,writer,indent+addindent,addindent,newl)
        writer.write("%s</%s>%s" % (indent,node.tagName,newl))

def CleanupVcproj(node):
  # For each sub node, we call recursively this function.
  for sub_node in node.childNodes:
    CleanupVcproj(sub_node)

  # For each node, take a copy, and remove it from the list.
  node_array = []
  while node.childNodes and node.childNodes[0]:
    # Take a copy of the node and remove it from the list.
    current = node.childNodes[0]
    node_array.append(current)
    node.removeChild(current)

  # Sort the list.
  if node.nodeName == 'ItemGroup':
    node_array.sort(CmpNode())

  for new_node in node_array:
    node.appendChild(new_node)

def main(argv):
  """Main function of this vcproj prettifier."""

  # check if we have exactly 1 parameter.
  if len(argv) < 1:
    print ('Usage: %s <vcproj.vcproj>' % argv[0])
    return
  # Open the vcproj and parse the xml.
  dom = parse(argv[1])

  CleanupVcproj(dom)

  sys.stdout.write('<?xml version="1.0" encoding="utf-8"?>\n')
  writexml(dom.documentElement, sys.stdout, "", "  ", "\n")

if __name__ == '__main__':
  main(sys.argv)
